package com.tudouji.framework.task;


import com.tudouji.common.enums.*;
import com.tudouji.common.utils.DateUtils;
import com.tudouji.common.utils.StringUtils;
import com.tudouji.project.bill.domain.*;
import com.tudouji.project.bill.service.*;
import com.tudouji.project.copy.domain.*;
import com.tudouji.project.copy.service.*;
import com.tudouji.project.customer.domain.Customer;
import com.tudouji.project.customer.service.ICustomerService;
import com.tudouji.project.organization.domain.Organization;
import com.tudouji.project.organization.domain.Supplier;
import com.tudouji.project.organization.service.IOrganizationService;
import com.tudouji.project.organization.service.ISupplierService;
import com.tudouji.project.product.domain.Salesspecification;
import com.tudouji.project.product.service.ISalesspecificationService;
import com.tudouji.project.store.domain.Stockunit;
import com.tudouji.project.store.domain.Storehouseroom;
import com.tudouji.project.store.domain.Storeroom;
import com.tudouji.project.store.service.IStockunitService;
import com.tudouji.project.store.service.IStorehouseroomService;
import com.tudouji.project.store.service.IStoreroomService;
import com.tudouji.project.system.domain.SysConfig;
import com.tudouji.project.system.service.ISysConfigService;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.Hlookup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 *  金蝶数据同步 第一步：生成待同步数据
 */
@Slf4j
@Component("dataExtraction")
public class DataExtraction {

    @Autowired
    private IWhoutformService whoutformService;

    @Autowired
    private ISysConfigService sysConfigService;

    @Autowired
    private ICopytokdService copytokdService;

    @Autowired
    private IWhoutformitemService whoutformitemService;

    @Autowired
    private ICopytokditemService copytokditemService;

    @Autowired
    private IMultipartConfigService multipartConfigService;

    @Autowired
    private ICopyparamService copyparamService;

    @Autowired
    private ISellformService sellformService;

    @Autowired
    private IOrganizationService organizationService;

    @Autowired
    private ISupplierService supplierService;

    @Autowired
    private ICustomerService customerService;

    @Autowired
    private IStoreroomService storeroomService;

    @Autowired
    private IStorehouseroomService storehouseroomService;

    @Autowired
    private ISalesspecificationService salesspecificationService;

    @Autowired
    private IWhinformService whinformService;

    @Autowired
    private IStockunitService stockunitService;

    @Autowired
    private IProducereportService producereportService;

    @Autowired
    private ITransferapplyitemService transferapplyitemService;

    @Autowired
    private ITransferapplyService transferapplyService;

    @Autowired
    private ISellitemService sellitemService;

    @Autowired
    private IWhinformitemService whinformitemService;

    @Autowired
    private DataExtraction dataExtraction;

    @Autowired
    private InnerPriceProcess innerPriceProcess;

    @Autowired
    private IDataexStopedtransService stopedtransService;

    private List<Customer> customerList = new ArrayList<Customer>();

    private List<Supplier> supplierList = new ArrayList<Supplier>();

    private List<Storehouseroom> storehouseroomList = new ArrayList<Storehouseroom>();

    private List<Storeroom> storeroomList = new ArrayList<Storeroom>();

    private List<Salesspecification> salesspecificationList = new ArrayList<Salesspecification>();

    private List<Stockunit> stockunitList = new ArrayList<Stockunit>();

    private List<Organization> organizationList = new ArrayList<Organization>();

    /**
     * 非标品内部结算价（比如7.5/公斤）参数，做为样品、赠送、促销订单的内部结算价
     */
    private BigDecimal innPrice;

    /**
     * 内部折扣
     */
    private BigDecimal innDiscount;


    private String kdncode = null;

    private static int i = 1;

    public void init() {
        customerList = this.customerService.selectCustomerList(new Customer());
        supplierList = this.supplierService.selectSupplierList(new Supplier());
        storehouseroomList = this.storehouseroomService.selectStorehouseroomList(new Storehouseroom());
        storeroomList = this.storeroomService.selectStoreroomList(new Storeroom());
        stockunitList = this.stockunitService.selectStockunitList(new Stockunit());
        salesspecificationList = this.salesspecificationService.selectSalesspecificationList(new Salesspecification());
        //把组织信息加进来
        organizationList = this.organizationService.selectOrganizationList(new Organization());
        innerPriceProcess.init(salesspecificationList,stockunitList,customerList,supplierList);
    }

    public void initInnPrice() {
        String price = this.sysConfigService.selectConfigByKey("inner_price");
        if (StringUtils.isNotEmpty(price)) {
            innPrice = new BigDecimal(price);
        }
    }

    public void initInnDiscount() {
        String dis = this.sysConfigService.selectConfigByKey("inner_discount");
        if (StringUtils.isNotEmpty(dis)) {
            innDiscount = new BigDecimal(dis);
        }
    }


    /**
     * 待同步数据
     */

    public void laterForm() throws Exception {
        log.debug("===============拉取数据开始====================");
        String proess = sysConfigService.selectConfigByKey("job_process");
        if ("1".equals(proess) || "3".equals(proess) || "5".equals(proess)) {
            return;
        }

        try {
            setProcessFlag("1");

            init();

            initInnPrice();

            initInnDiscount();

            Copyparam copyparam = new Copyparam();
            copyparam.setIscopy(IsCopyEnums.YES.getCode());
            copyparam.setKind(KindEnums.BILL.getCode());
            List<Copyparam> copyparamList = this.copyparamService.selectCopyparamList(copyparam);
            for (Copyparam c : copyparamList) {
                //入库单
                if (StringUtils.isNotEmpty(c.getIntype())) {
                    dataExtraction.laterInform(c.getIntype(), c.getStartdate(), c);
                }
                //出库单
                if (StringUtils.isNotEmpty(c.getOuttype())) {
                    dataExtraction.laterOutform(c.getOuttype(), c.getStartdate(), c);
                }
                if (StringUtils.isEmpty(c.getIntype()) && StringUtils.isEmpty(c.getOuttype())) {
                    if (c.getType().equals(CopyTypeEnums.PRODUCTION_OUT.getCode())) {
                        //生产出库，从生产报表中拉去数据
                        //拉去成功后将生产计划的状态置成5
                        productionOut(c.getStartdate(), c);
                    } else if (c.getType().equals(CopyTypeEnums.REDEPLOY.getCode())) {
                        //调拨出入库
                        //查询已完成的调拨单，然后按照调拨单明细查询写入待处理，并且将调拨单的Iscopy字段更新为1
//  20220518注释掉用新的业务逻辑处理                      redeploy(c);

                    }
                }
            }

            //删除stop中 所有whin_autoid > copytokd中的调拨入库单id 的数据
            stopedtransService.deleteDataexStopedLargeWhinId();
            //删除stop中 所有whout_autoid > copytokd中的调拨出库单id 的数据
            stopedtransService.deleteDataexStopedLargeWhoutId();

        } catch (Exception e) {
//            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            e.printStackTrace();
            log.debug(e.getMessage());
        } finally {
            setProcessFlag("2");
        }
    }

    /**
     * 设置开始处理参数，控制处理过程，以及手工发起是能够通过前端查看处理进度
     */
    public void setProcessFlag(String processFlag) {
        SysConfig sysConfig = this.sysConfigService.selectConfigById(4L);
        sysConfig.setConfigValue(processFlag);
        this.sysConfigService.updateConfig(sysConfig);
    }


    /**
     * 反向生成待同步数据
     *
     * @param copytokd
     */
    public void reverseTransferapply(Copytokd copytokd) {
        copytokd.setTotalqty(BigDecimal.ZERO.subtract(copytokd.getTotalqty()));
        //copytokd.setTotalamount(BigDecimal.ZERO.subtract(copytokd.getTotalamount()));
        copytokd.setStatus(CopyStatusEnums.INIT.getCode());
        copytokd.setKdcode(copytokd.getCode() + getI(copytokd.getCode()));
        copytokd.setPushdate(null);
        this.copytokdService.insertCopytokd(copytokd);
        for (Copytokditem item : copytokd.getCopytokditemList()) {
            item.setCtkdid(copytokd.getId());
            item.setQty(BigDecimal.ZERO.subtract(item.getQty()));
            item.setKdqty(BigDecimal.ZERO.subtract(item.getKdqty()));
            item.setAmount(BigDecimal.ZERO.subtract(item.getAmount()));
            item.setStatus(CopyStatusEnums.INIT.getCode());
            this.copytokditemService.insertCopytokditem(item);
        }
    }


    /**
     * 待同步入库单
     *
     * @throws Exception
     */
    public void laterInform(String types, Date startdate, Copyparam copyparam) throws Exception {
        // List<Supplier> supplierList = this.supplierService.selectSupplierList(new Supplier());
        Date date = DateUtils.getNowDate();
        Copytokd copytokd = new Copytokd();
        copytokd.setType(BillTypeEnums.IN.getCode());
        copytokd.setSubtypes(types);

        Long autoid = this.copytokdService.getMaxlinkedid(copytokd);

        Whinform whinform = new Whinform();
        if (StringUtils.isNotEmpty(copyparam.getConditions())) {
            whinform.setConditions(copyparam.getConditions());
        }
        whinform.setTypes(types);
        whinform.setNotisCopytoKD(2);
        if (autoid > 0) {
            whinform.setAutoid(autoid);
        } else {
            whinform.setBeginCreatedate(startdate);
            whinform.setEndCreatedate(DateUtils.getDateBeforeMinite(date, -3));
        }

        List<Whinform> whinformList = this.whinformService.selectWhinformBaseList(whinform);
        //调拨入库历史失败数据处理
        List<Whinform> whinforms=new ArrayList<>();
        if (copyparam.getType().equals(CopyTypeEnums.REDEPLOY.getCode())) {
            whinforms=whinformService.selectWhinformsHistory();
            if(whinforms!=null){
                whinforms.forEach(item->{
                    Transferapply apply=transferapplyService.selectTransferapplyById(item.getFoguid());
                    if(apply.getStatus()==100){
                        dataExtraction.redeployIn(item,copyparam);
                        stopedtransService.deleteDataexStopedtransByWhinId(item.getAutoid());
                    }
                });
            }
        }

        if (whinformList.size() > 0) {
            for (Whinform wif : whinformList) {

                //20231129 查询主表不再包含子表数据，子表数据重新单独查询
                Whinformitem lookup = new Whinformitem();
                lookup.setWhinid(wif.getGuid());
                List<Whinformitem> whinformitems=whinformitemService.selectWhinformitemList(lookup);
                wif.setWhinformitemList(whinformitems);


                if (wif.getWhinformitemList().size() > 0) {
                    if (copyparam.getType().equals(CopyTypeEnums.REDEPLOY.getCode())) {
                        //调拨入库,20220518放开,按照新的逻辑跑调拨入库
                        dataExtraction.redeployIn(wif,copyparam);
                    } else if (copyparam.getType() == CopyTypeEnums.PURCHASING.getCode()) {
                        //采购入库
//                        purchasingIn(wif, date);
                        dataExtraction.purchasingIn(wif);
                    } else if (copyparam.getType() == CopyTypeEnums.PRODUCTION.getCode()) {
                        //生产入库
                        dataExtraction.productionIn(wif);
                    } else if (copyparam.getType() == CopyTypeEnums.JUSTING.getCode()) {
                        //调整入库
//                        justingIn(wif, date);
                        dataExtraction.justingIn(wif);
                    } else if (copyparam.getType() == CopyTypeEnums.BACK.getCode()) {
                        //退料入库
//                        backIn(wif, date);
                        dataExtraction.backIn(wif);
                    } else if (copyparam.getType() == CopyTypeEnums.HARVEST.getCode()) {
                        //采收入库
//                        harvestn(wif, date);
                        dataExtraction.harvestn(wif);
                    } else {
                        log.info("没有找到入库类型的数据或者调拨单未完成");
                    }
                }

            }

        }
    }

    /**
     * 待同步出库单
     *
     * @throws Exception
     */
    public void laterOutform(String types, Date startdate, Copyparam copyparam) throws Exception {

        Date date = DateUtils.getNowDate();

        Copytokd copytokd = new Copytokd();
        //同步数据类型 为出库单
        copytokd.setType(BillTypeEnums.OUT.getCode());
        //子类型 为出库单
        copytokd.setSubtypes(types);
        //获取已同步的 最大autoid
        Long autoid = this.copytokdService.getMaxlinkedid(copytokd);

        Whoutform whoutform = new Whoutform();
        if (StringUtils.isNotEmpty(copyparam.getConditions())) {
            whoutform.setConditions(copyparam.getConditions());
        }
        whoutform.setTypes(types);
        whoutform.setNotisCopytoKD(2);

        //只查询销售出库单SF2204187，测试赠送的数据拆分
//        whoutform.setBusinesscode("SF2204187");

        if (autoid > 0) {
            whoutform.setAutoid(autoid);
        } else {
            whoutform.setBeginCreatedate(startdate);
            whoutform.setEndCreatedate(DateUtils.getDateBeforeMinite(date, -3));
        }

        List<Whoutform> whoutformList = this.whoutformService.selectWhoutformList(whoutform);

        //调拨历史拉取失败数据处理
        List<Whoutform> whoutforms =new ArrayList<>();
        if (copyparam.getType().equals(CopyTypeEnums.REDEPLOY.getCode())){
            whoutforms= whoutformService.selectWhoutformsHistory();
            if(whoutforms!=null){
                whoutforms.forEach(item->{
                    Transferapply apply=transferapplyService.selectTransferapplyById(item.getOrderguid());
                    if(apply.getStatus()==100){
                        redeployOut(item,copyparam);
                        stopedtransService.deleteDataexStopedtransByWhoutId(item.getAutoid());
                    }
                });
            }
        }
        for (Whoutform wof : whoutformList) {
            //20231129 出库单主表查询不关联出库单明细表，针对每一条出库单主表数据单独查询
            Whoutformitem lookup = new Whoutformitem();
            lookup.setWhoutid(wof.getGuid());
            List<Whoutformitem> whoutformitems = whoutformitemService.selectWhoutformitemList(lookup);
            wof.setWhoutformitemList(whoutformitems);

            if (wof.getWhoutformitemList().size() > 0) {
                if (copyparam.getType().equals(CopyTypeEnums.SALE.getCode())) {
                    //处理销售出库
                    dataExtraction.saleOut(wof, date);
                } else if (copyparam.getType().equals(CopyTypeEnums.REDEPLOY.getCode())) {
                    //调拨出库,20220518,根据新的设计逻辑重新实现调拨单数据抽取
                    dataExtraction.redeployOut(wof,copyparam);
                } else if (copyparam.getType().equals( CopyTypeEnums.PRODUCTION.getCode())) {
                    //生产领料出库
                    //productionOut(wof, date);
                } else if (copyparam.getType().equals(CopyTypeEnums.JUSTING.getCode())) {
                    //调整出库
                    dataExtraction.justingOut(wof, date);
                } else if (copyparam.getType().equals(CopyTypeEnums.SCRAPPING.getCode())) {
                    //报废出库
                    dataExtraction.scrappingOut(wof, date);
                } else {
                    log.info("没有找到出库类型的数据或者调拨单未完成,出库单：{},业务单号：{}",wof.getWhoutcode(),wof.getBusinesscode());
                }
            }
        }
    }

    /**
     * 退料入库单
     *
     * @param wif
     */
    //前方法必须运行在它自己的事务中。一个新的事务将启动，而且如果有一个现有的事务在运行的话，则这个方法将在运行期被挂起，直到新的事务提交或者回滚才恢复执行
    @Transactional(propagation= Propagation.REQUIRES_NEW)
    public void backIn(Whinform wif) {
        generateWhinCopyData(wif, WhinformTypeEnums.BACK.getCode(),KDWhinformTypeEnums.OTHER.getCode());
    }

    /**
     * 调拨入库单
     *
     * @param wif
     */
    @Transactional(propagation= Propagation.REQUIRES_NEW)
    public void redeployIn(Whinform wif,Copyparam copyparam) {
        //校验调拨单是否完成  未完成设置 isTransferFinish=false
        Transferapply apply=transferapplyService.selectTransferapplyById(wif.getFoguid());
        if(apply.getStatus()!=100){
            DataexStopedtrans stoppers=new DataexStopedtrans();
            stoppers.setWhinAutoid(wif.getAutoid());
            stoppers.setBusinessCode(wif.getBusinesscode());
            //20230704 首先检查是否已存在
            List<DataexStopedtrans> stopList = stopedtransService.selectDataexStopedtransList(stoppers);
            if(stopList.size()==0){
                stopedtransService.insertDataexStopedtrans(stoppers);
            }
        }else{
            //判断同组织还是跨组织调拨
            if (wif.getOrgguid().equals(wif.getSettlOrgId())){
                //同组织调拨
                processTransForSameOrgs(wif);
            }else{
                //跨组织调拨
                processTransInForDifOrgs(wif,copyparam);
            }
        }
        return;
    }


    /**
     * 跨组织调拨单入库数据推送数据
     * @param wif
     * @return
     */
    private void processTransInForDifOrgs(Whinform wif, Copyparam copyparam){
        //如果是反向交易，需要考虑冲回处理
        if(wif.getQty().compareTo(BigDecimal.ZERO)<0){
//            generateWhinCopyData(wif,WhinformTypeEnums.REDEPLOY.getCode());
            return;
        }

        String transApplyGuid = wif.getFoguid();
        //takeByfromSide = true 调入方承担差额 否则，调出方承担
        boolean takeByfromSide =  copyparam.getParam().equals("1");
        if (wif.getWhinformitemList() != null) {
            for (Whinformitem whinformitem : wif.getWhinformitemList()) {
                processTransInDifference(wif,whinformitem, transApplyGuid, takeByfromSide);
            }
        }

    }

    /**
     * 跨组织调拨单出库数据推送数据
     * @param whoutform
     * @return
     */
    private void processTransOutForDifOrgs(Whoutform whoutform,Copyparam copyparam){
        //如果是反向交易，需要考虑冲回处理
        if(whoutform.getWeight().compareTo(BigDecimal.ZERO)<0){
//            generateWhinCopyData(wif,WhinformTypeEnums.REDEPLOY.getCode());
            return;
        }

        String transApplyGuid = whoutform.getOrderguid();
        //takeByfromSide = true 调入方承担差额 否则，调出方承担
        boolean takeByfromSide =  copyparam.getParam().equals("1");
        if (whoutform.getWhoutformitemList() != null) {
            for (Whoutformitem whoutformitem : whoutform.getWhoutformitemList()) {
                processTransOutDifference(whoutform,whoutformitem, transApplyGuid, takeByfromSide);
            }
        }

    }


    private Whinform wrapeWhinform(Whinform whinform,Whinformitem whinformitem,BigDecimal qty,BigDecimal innerPriceForTrans){
        Whinform result = new Whinform();
//        result = whinform.clone;
        result.setAutoid(whinform.getAutoid());
        result.setBusinesscode(whinform.getBusinesscode());
        result.setCarcode(whinform.getCarcode());
        result.setCreatedate(whinform.getCreatedate());
        result.setBeginCreatedate(whinform.getBeginCreatedate());
        result.setWhintype(whinform.getWhintype());
        result.setFoguid(whinform.getFoguid());
        result.setGuid(whinform.getGuid());
        result.setCurrency(whinform.getCurrency());

        result.setStorermguid(whinform.getStorermguid());
        result.setSrname(whinform.getSrname());

        result.setDepartmentid(whinform.getDepartmentid());
        result.setIsCopytoKD(whinform.getIsCopytoKD());
        result.setFormno(whinform.getFormno());
        result.setOperator(whinform.getOperator());
        result.setOperatorid(whinform.getOperatorid());
        result.setOrgguid(whinform.getOrgguid());
        result.setOrgname(whinform.getOrgname());
        result.setSettlOrgId(whinform.getSettlOrgId());
        result.setSettlOrgName(whinform.getSettlOrgName());
        if (whinform.getSettlOrgId() != null){
            List<Supplier> suppliers = supplierList.stream().filter(s -> whinform.getSettlOrgId().equals(s.getOrgguid())).collect(Collectors.toList());
            if (suppliers.size() > 0) {
                result.setSupplierId(suppliers.get(0).getId());
                result.setSupplierName(suppliers.get(0).getName());
            }else{
                log.info(" Should set inner supplier for org:"+ whinform.getSettlOrgId());
            }

        }



        if (qty == null){
            result.setQty(whinform.getQty());
        }else{
            result.setQty(qty);
        }
        ArrayList<Whinformitem> whinformitems = new ArrayList<>();
        whinformitem.setPrice(innerPriceForTrans);
        //调拨入库单业务层没有计算结算金额
        whinformitem.setAmount(whinformitem.getWeight().multiply(innerPriceForTrans));
        if (qty == null){
            whinformitem.setWeight(whinform.getQty());
        }else{
            whinformitem.setWeight(qty);
        }
        whinformitems.add(whinformitem);
        result.setWhinformitemList(whinformitems);

        return result;
    }

    private Whoutform wrapeWhoutform(Whoutform whoutform,Whoutformitem whoutformitem,BigDecimal qty,BigDecimal innerPriceForTrans){
        Whoutform result = new Whoutform();
//        result = whinform.clone;
        result.setAutoid(whoutform.getAutoid());
        result.setBusinesscode(whoutform.getBusinesscode());
        result.setCarcode(whoutform.getCarcode());

        result.setBeginCreatedate(whoutform.getBeginCreatedate());
        result.setOuttype(whoutform.getOuttype());
        result.setOrderguid(whoutform.getOrderguid());
        result.setGuid(whoutform.getGuid());
        result.setCurrency(whoutform.getCurrency());

        result.setSrguid(whoutform.getSrguid());

        result.setDepartmentid(whoutform.getDepartmentid());
        result.setIsCopytoKD(whoutform.getIsCopytoKD());

        result.setOperator(whoutform.getOperator());
        result.setOperatorid(whoutform.getOperatorid());
        result.setOrgguid(whoutform.getOrgguid());
        result.setOrgname(whoutform.getOrgname());
        result.setSettlOrgId(whoutform.getSettlOrgId());
        result.setSettlOrgName(whoutform.getSettlOrgName());
        result.setWhoutcode(whoutform.getWhoutcode());
        //20231129统一用出库单的创建时间作为业务时间
        //result.setOuttime(whoutform.getOuttime());
        result.setOuttime(whoutform.getCreatetime());
        result.setCreatetime(whoutform.getCreatetime());

        //内部销售出库单的，内部客户获取


        if(whoutform.getSettlOrgId()!=null){
            List<Customer> customers = customerList.stream().filter(c -> whoutform.getSettlOrgId().equals(c.getOrgguid())).collect(Collectors.toList());
            if (customers.size() == 1) {
                result.setRevCustId(customers.get(0).getGuid());
                result.setRevCustName(customers.get(0).getName());
            }else{
                log.error("cannt find inner customer for transferapply :" + whoutform.getBusinesscode()
                        +",of whoutcode:"+whoutform.getWhoutcode() +",of settleOrgId:"+whoutform.getSettlOrgId());
                throw new RuntimeException();
            }
        }

        if (qty == null){
            result.setWeight(whoutform.getWeight());
        }else{
            result.setWeight(qty);
            whoutformitem.setWeight(qty);
        }
        ArrayList<Whoutformitem> whoutformitems = new ArrayList<>();
        whoutformitem.setPrice(innerPriceForTrans);
        //20240426 采用StockUnitPrice最为最终的结算价格
        whoutformitem.setStockUnitPrice(innerPriceForTrans);

        //调拨入库单业务层没有计算结算金额
//        whoutformitem.setAmount (whoutformitem.getWeight().multiply(innerPriceForTrans));
        whoutformitems.add(whoutformitem);
        result.setWhoutformitemList(whoutformitems);

        return result;
    }
    /**
     * 调拨单调入方的入库单数据，生成差额部分的出库单相关数据
     * @param whinform
     * @param whinformitem
     * @param qty
     * @return
     */
    private Whoutform wrapeWhoutform(Whinform whinform,Whinformitem whinformitem,BigDecimal qty,BigDecimal innerPriceForTrans){
        Whoutform result = new Whoutform();
        result.setAutoid(whinform.getAutoid());
        result.setBusinesscode(whinform.getBusinesscode());
        result.setCarcode(whinform.getCarcode());
        result.setCreatetime(whinform.getCreatedate());
        result.setBeginCreatedate(whinform.getBeginCreatedate());
        result.setOuttype(WhinformTypeEnums.REDEPLOY.getCode());
        result.setOrderguid(whinform.getFoguid());
        result.setGuid(whinform.getGuid());
        result.setCurrency(whinform.getCurrency());
        result.setWhoutcode(whinform.getFormno());

        result.setSrguid(whinform.getStorermguid());

        result.setDepartmentid(whinform.getDepartmentid());
        result.setIsCopytoKD(whinform.getIsCopytoKD());

        result.setOperator(whinform.getOperator());
        result.setOperatorid(whinform.getOperatorid());
        result.setOrgguid(whinform.getOrgguid());
        result.setOrgname(whinform.getOrgname());
        result.setSettlOrgId(whinform.getSettlOrgId());
        result.setSettlOrgName(whinform.getSettlOrgName());

        result.setOuttime(whinform.getCreatedate());

        Whoutformitem whoutformitem = new Whoutformitem();
        if (qty == null){
            result.setWeight(whinform.getQty());
            whoutformitem.setWeight(whinformitem.getWeight());
        }else{
            result.setWeight(qty);
            whoutformitem.setWeight(qty);
        }
        ArrayList<Whoutformitem> whoutformitems = new ArrayList<>();
        whoutformitem.setOrgguid(whinformitem.getOrgguid());
        whoutformitem.setOrgname(whinformitem.getOrgname());

        whoutformitem.setProductguid(whinformitem.getProductguid());
        whoutformitem.setProduct(whinformitem.getProduct());
        whoutformitem.setSpguid(whinformitem.getSpguid());
        whoutformitem.setSpename(whinformitem.getSpename());

        whoutformitem.setSrguid(whinformitem.getSrguid());
        whoutformitem.setShrguid(whinformitem.getShrguid());
        whoutformitem.setStockunitid(whinformitem.getStockunitid());
        whoutformitem.setStockunit(whinformitem.getStockunit());
        whoutformitem.setPrice(innerPriceForTrans);
        //20240426 采用StockUnitPrice最为最终的结算价格
        whoutformitem.setStockUnitPrice(innerPriceForTrans);
        whoutformitems.add(whoutformitem);
        result.setWhoutformitemList(whoutformitems);

        return result;
    }

    private void processTransForSameOrgs(Whinform wif){
        Date date=new Date();
        //写入同步数据主表信息
        Copytokd copytokd = new Copytokd();
        copytokd.setCopyRemark("");
        copytokd.setLinkedautoid(wif.getAutoid());
        copytokd.setLinkedcode(wif.getFormno());
        copytokd.setOrderguid(wif.getGuid());
        copytokd.setCode(wif.getBusinesscode());
        copytokd.setSrguid(wif.getStorermguid());
        copytokd.setCurrency(wif.getCurrency());
        copytokd.setKdcode(wif.getBusinesscode() + "A" + i);
        copytokd.setType(BillTypeEnums.IN.getCode());
        copytokd.setSubtype(wif.getWhintype());
        copytokd.setKdtype(KDWhinformTypeEnums.STOCK_TRANSFER.getCode());
        copytokd.setDepartmentid(wif.getDepartmentid());
        copytokd.setOrgguid(wif.getOrgguid());
        copytokd.setOrgname(wif.getOrgname());
        copytokd.setTotalqty(wif.getQty());
        copytokd.setTotalamount(wif.getPrice());
        //初始状态
        copytokd.setStatus(CopyStatusEnums.INIT.getCode());
        copytokd.setOperator(wif.getOperatorid());
        copytokd.setOrderdate(wif.getCreatedate());
        copytokd.setCopyTime(date);
        copytokd.setLastCopyTime(date);
        copytokd.setCreatetime(date);
        copytokd.setIssplit(IssplitEnums.NO.getCode());
        //插入主表数据
        this.copytokdService.insertCopytokd(copytokd);
        Long copyId = copytokd.getId();
        //获取并插入明细数据，下一步改造为懒加载
        if (wif.getWhinformitemList() != null) {
            for (Whinformitem item : wif.getWhinformitemList()) {
                //获取当前调拨单、当前入库明细对应的物料规格的所有出库汇总数量
                Whoutformitem outItem=new Whoutformitem();
                outItem.setSpguid(item.getSpguid());
                outItem.setOrderId(wif.getFoguid());
                outItem =whoutformitemService.selectWhoutItemBySpeId(outItem);

                Whoutform outform=whoutformService.selectWhoutformByGuid(outItem.getWhoutid());

                Copytokditem copytokditem = new Copytokditem();
                copytokditem.setCtkdid(copyId);
                //调出库房 库间
                copytokditem.setSrguid(outItem.getSrguid());
                copytokditem.setShrguid(outItem.getShrguid());
                //20231129 统一用出库单的创建时间作为业务时间
                //copytokditem.setOutDate(outform.getOuttime()!=null?outform.getOuttime():outform.getCreatetime());
                copytokditem.setOutDate(outform.getCreatetime());
                //调入库房 库间
                copytokditem.setToSRGuid(item.getSrguid());
                copytokditem.setToSHRguid(item.getShrguid());
                copytokditem.setInDate(wif.getCreatedate());

                copytokditem.setOrgguid(item.getOrgguid());
                copytokditem.setOrgname(item.getOrgname());
                copytokditem.setProductguid(item.getProductguid());
                if (StringUtils.isNotEmpty(item.getSpguid())) {
                    copytokditem.setSpguid(item.getSpguid());
                } else {
                    copytokditem.setSpguid(item.getRawspguid());
                }
                copytokditem.setQty(item.getWeight());
                setCopytokdAmount(copytokditem,item.getAmount());
                //转换入库数量（按照金蝶系统和ERP系统的库存单位转换）
                getQtyIn(copytokditem, item);

                //记录新增加的入库单明细的id
                copytokditem.setWhinoroutitemGuid(item.getGuid());
                copytokditem.setIspresent(IsPresentKDEnums.FALSE.getCode());
                copytokditem.setUnit(item.getStockunit());
                copytokditem.setUnitid(item.getStockunitid());
                copytokditem.setCreatedate(date);
                copytokditem.setCopyTime(date);
                copytokditem.setStatus(CopyStatusEnums.INIT.getCode());
                //20230306 写入新增的入库单详情的guid
                copytokditem.setWhinoroutitemGuid(item.getGuid());

                this.copytokditemService.insertCopytokditem(copytokditem);
            }
        }

    }
    /**
     * 统计当前调拨入库单明细对应的物料，在本次调拨中的出库、入库差额
     * @param whinformitem
     * @return
     */
    private void processTransInDifference(Whinform whinform, Whinformitem whinformitem, String transApplyGuid, boolean takeByfromSide){
        //获取到调拨单,需要处理
        Transferapply transferapply = transferapplyService.selectTransferapplyById(transApplyGuid);

        //获取到当前调拨出库明细表对应的调拨单明细表，得到单价
        Transferapplyitem transferapplyitem=new Transferapplyitem();
        transferapplyitem.setTransferguid(transApplyGuid);
        transferapplyitem.setSpguid(whinformitem.getSpguid());
        BigDecimal innerPriceForTrans = transferapplyitemService.selectPriceBySpeId(transferapplyitem);


        //获取当前调拨单、当前入库明细对应的物料规格的所有出库汇总数量
        Whoutformitem outItem=new Whoutformitem();
        outItem.setSpguid(whinformitem.getSpguid());
        outItem.setOrderId(transApplyGuid);
        BigDecimal transOut =whoutformitemService.sumCountByOrderIdAndSpeId(outItem);

        //获取当前调拨单的当前入库明细对应的物料规格的所有入库汇总数量
        whinformitem.setOrderId(transApplyGuid);
        BigDecimal transIn = whinformitemService.sumCountByOrderIdAndSpeId(whinformitem);

        BigDecimal diff = transIn.subtract(transOut);

        Whinform tbpWhinform = null;

        if (diff.compareTo(BigDecimal.ZERO) == 0
            || (diff.compareTo(BigDecimal.ZERO) < 0 && !takeByfromSide)){
            //调入调出数量相等，或者调入小于调出、调出方承担差额的，以调入数量生成采购入库单即可
            tbpWhinform = wrapeWhinform(whinform,whinformitem,transIn,innerPriceForTrans);
            generateWhinCopyData(tbpWhinform,WhinformTypeEnums.REDEPLOY.getCode(), KDWhinformTypeEnums.PURCHASING.getCode());
            return;
        }

        //调入小于调出，调入方承担的，或者调入大于调出的
        //调出数量的采购入库
        tbpWhinform = wrapeWhinform(whinform,whinformitem,transOut,innerPriceForTrans);
        generateWhinCopyData(tbpWhinform,WhinformTypeEnums.REDEPLOY.getCode(), KDWhinformTypeEnums.PURCHASING.getCode());
        //差额部分需调入方的生成其他出库单
        BigDecimal positive_diff = diff;
        if (diff.compareTo(BigDecimal.ZERO) < 0 ){
            positive_diff = BigDecimal.ZERO.subtract(diff);
        }
        if(diff.compareTo(BigDecimal.ZERO) < 0){
            //调入小于调出，差额部分的调入方其他出库单
            Whoutform tbpWhoutform = wrapeWhoutform(whinform,whinformitem,positive_diff,innerPriceForTrans);
            Copytokd copytokd = new Copytokd();
            //whouseType = 1 从原始库房出库
            generateWhoutCopyData(copytokd,tbpWhoutform,null,WhoutformTypeEnums.REDEPLOY.getCode(),1,false,KDWhoutformTypeEnums.OTHER.getCode(),null);

        }else{
            //调入大于调出，差额部分的调入方的其他入库单
            Whinform tbpWhinfrom = wrapeWhinform(whinform,whinformitem,positive_diff,innerPriceForTrans);
            generateWhinCopyData(tbpWhinfrom,WhinformTypeEnums.REDEPLOY.getCode(), KDWhinformTypeEnums.OTHER.getCode());
        }
        return;


    }

    /**
     * 处理跨组织调拨出库单的推送数据
     * @param whoutformitem
     * @return
     */
    private void processTransOutDifference(Whoutform whoutform, Whoutformitem whoutformitem, String transApplyGuid, boolean takeByfromSide){
        //获取到调拨单,需要处理
        Transferapply transferapply = transferapplyService.selectTransferapplyById(transApplyGuid);

        //获取到当前调拨出库明细表对应的调拨单明细表，得到单价
        Transferapplyitem transferapplyitem=new Transferapplyitem();
        transferapplyitem.setTransferguid(transApplyGuid);
        transferapplyitem.setSpguid(whoutformitem.getSpguid());
        BigDecimal innerPriceForTrans = transferapplyitemService.selectPriceBySpeId(transferapplyitem);

        //调拨出库数量
        BigDecimal transOut = whoutformitem.getWeight();

        //获取当前调拨单、当前出库明细对应的物料规格的所有入库汇总数量，需要处理***
        Whinformitem whinformitem = new Whinformitem();
        whinformitem.setOrderId(transApplyGuid);
        whinformitem.setSpguid(whoutformitem.getSpguid());
        BigDecimal transIn = whinformitemService.sumCountByOrderIdAndSpeId(whinformitem);

        BigDecimal diff = transIn.subtract(transOut);

        Whoutform tbpWhoutform = null;
        Copytokd copytokd = null;
        if (diff.compareTo(BigDecimal.ZERO) == 0
            || (diff.compareTo(BigDecimal.ZERO) < 0 && takeByfromSide)
                || diff.compareTo(BigDecimal.ZERO) > 0 ){
            //调入调出数量相等，或者调入小于调出且调入方承担差额，或者调入大于调出，生成销售出库单即可
            tbpWhoutform =wrapeWhoutform(whoutform,whoutformitem,transOut,innerPriceForTrans);
            copytokd = new Copytokd();
            generateWhoutCopyData(copytokd, tbpWhoutform,null,WhoutformTypeEnums.REDEPLOY.getCode(),1,false,KDWhoutformTypeEnums.SALE.getCode(), null);
            return;
        }


        //调入小于调出数量,调出方承担差额，差额部分其他出库单
        BigDecimal positive_dff = diff;
        if (diff.compareTo(BigDecimal.ZERO) < 0 ){
            positive_dff = BigDecimal.ZERO.subtract(diff);
        }
        tbpWhoutform = wrapeWhoutform(whoutform,whoutformitem,positive_dff,innerPriceForTrans);
        copytokd = new Copytokd();
        generateWhoutCopyData(copytokd, tbpWhoutform,null,WhoutformTypeEnums.REDEPLOY.getCode(),1,false,KDWhoutformTypeEnums.OTHER.getCode(), null);
        //调入部分销售出库单
        tbpWhoutform = wrapeWhoutform(whoutform,whoutformitem,transIn,innerPriceForTrans);
        copytokd = new Copytokd();
        generateWhoutCopyData(copytokd, tbpWhoutform,null,WhoutformTypeEnums.REDEPLOY.getCode(),1,false,KDWhoutformTypeEnums.SALE.getCode(), null);
        return;
    }

    /**
     * 采购入库
     *
     * @param wif
     */
    @Transactional(propagation= Propagation.REQUIRES_NEW)
    public void purchasingIn(Whinform wif) {
        generateWhinCopyData(wif, WhinformTypeEnums.PURCHASING.getCode(),KDWhinformTypeEnums.PURCHASING.getCode());
    }

    /**
     * 根据ERP入库单数据，生成待同步入库单
     *
     * @param wif      ERP系统入库单
     * @param whinType
     */
    public void generateWhinCopyData(Whinform wif, int whinType,@NonNull String kingdeeType) {
        Date date = DateUtils.getNowDate();
        getI(wif.getBusinesscode());
        Copytokd copytokd = new Copytokd();
        copytokd.setCopyRemark("");
        copytokd.setLinkedautoid(wif.getAutoid());
        copytokd.setLinkedcode(wif.getFormno());
        copytokd.setOrderguid(wif.getGuid());
        copytokd.setCode(wif.getBusinesscode());
        copytokd.setSrguid(wif.getStorermguid());
        copytokd.setCurrency(wif.getCurrency());
        copytokd.setKdcode(wif.getBusinesscode() + "A" + i);
        copytokd.setType(BillTypeEnums.IN.getCode());
        copytokd.setSubtype(wif.getWhintype());

        copytokd.setKdtype(kingdeeType);

        copytokd.setSrguid(wif.getStorermguid());
        copytokd.setDepartmentid(wif.getDepartmentid());
        copytokd.setOrgguid(wif.getOrgguid());
        copytokd.setOrgname(wif.getOrgname());
        copytokd.setTotalqty(wif.getQty());
        copytokd.setTotalamount(wif.getPrice());
        //采购入库单需要供应商
        if (copytokd.getKdtype().equals(KDWhinformTypeEnums.PURCHASING.getCode())) {
            copytokd.setSupplierid(wif.getSupplierId());
        }

        //初始状态
        copytokd.setStatus(CopyStatusEnums.INIT.getCode());
        copytokd.setOperator(wif.getOperatorid());

        copytokd.setOrderdate(wif.getCreatedate());

        copytokd.setCopyTime(date);
        copytokd.setLastCopyTime(date);
        copytokd.setCreatetime(date);

        copytokd.setIssplit(IssplitEnums.NO.getCode());
        //插入主表数据
        this.copytokdService.insertCopytokd(copytokd);
        Long copyId = copytokd.getId();
        //获取并插入明细数据，下一步改造为懒加载
        if (wif.getWhinformitemList() != null) {
            for (Whinformitem item : wif.getWhinformitemList()) {
                boolean flagitem = true;
                Copytokditem copytokditem = new Copytokditem();
                copytokditem.setCtkdid(copyId);
                copytokditem.setSrguid(item.getSrguid());
                copytokditem.setShrguid(item.getShrguid());
                copytokditem.setOrgguid(item.getOrgguid());
                copytokditem.setOrgname(item.getOrgname());
                copytokditem.setProductguid(item.getProductguid());
                if (StringUtils.isNotEmpty(item.getSpguid())) {
                    copytokditem.setSpguid(item.getSpguid());
                } else {
                    copytokditem.setSpguid(item.getRawspguid());
                }

//                copytokditem.setAmount(item.getAmount());
                copytokditem.setQty(item.getWeight());
                log.error("item.getAmount(): " + item.getAmount());
                setCopytokdAmount(copytokditem,item.getAmount());
                //转换入库数量（按照金蝶系统和ERP系统的库存单位转换）
                getQtyIn(copytokditem, item);
                //采购入库单需要计算单价，以及，获取销售组织

                if (kingdeeType.equals(KDWhinformTypeEnums.PURCHASING.getCode())) {
                    // 采收入库单，按照采收的规则获取结算金额
                    //20240520 采收结算金额应该从入库单获取，不应该从采收订单再次获取了，因为采收
                    //订单可能会再次结算，导致推送数据错误
                    /** 20240520
                     if (whinType == WhinformTypeEnums.HARVEST.getCode()) {
                     BigDecimal amount = this.copytokdService.getSettlement(wif.getFoguid());
                     //                        copytokditem.setAmount(amount);
                     setCopytokdAmount(copytokditem,amount);
                     } 20240520 **/
                    if(whinType==WhinformTypeEnums.PRODUCTION.getCode()){
                        copytokditem.setPrice(BigDecimal.ZERO);
                    }else{
                        if (copytokditem.getKdqty() != null) {
                            copytokditem.setPrice(copytokditem.getAmount().divide(copytokditem.getKdqty(), 6, RoundingMode.HALF_UP));
                        }
                    }

                    copytokditem.setSaleorgid(wif.getSettlOrgId());
                    //采购入库单需要计算单价，所以，放在采购入库单的主逻辑里
                    copytokditem.setSupplierid(wif.getSupplierId());
                    copytokditem.setBalancesupplierid(wif.getSupplierId());

                }

                //这个也是采购入库单的，待检查
                copytokditem.setIspresent(IsPresentKDEnums.FALSE.getCode());
                copytokditem.setUnit(item.getStockunit());
                copytokditem.setUnitid(item.getStockunitid());

                //copytokditem.set
                copytokditem.setCreatedate(date);
                copytokditem.setCopyTime(date);

                copytokditem.setStatus(CopyStatusEnums.INIT.getCode());

                //20230306 写入新增的入库单详情的guid
                copytokditem.setWhinoroutitemGuid(item.getGuid());
                this.copytokditemService.insertCopytokditem(copytokditem);
            }
        }
    }

    /**
     * 设置copytokditem的amount，对于反向交易，需要设置amount为负数
     * 调用前提：copytokditem.setQty（）已完成调用
     * @param copytokditem
     * @param amount
     */
    private void setCopytokdAmount(Copytokditem copytokditem,BigDecimal amount){
        if(amount == null || copytokditem.getQty() == null){
            return;
        }
        if (amount.compareTo(BigDecimal.ZERO) > 0 &&
                copytokditem.getQty().compareTo(BigDecimal.ZERO) < 0){
            copytokditem.setAmount(amount.multiply(BigDecimal.valueOf(-1)));
            return;
        }
        copytokditem.setAmount(amount);
        return;
    }


    /**
     * 采收入库
     *
     * @param wif ERP采收入库单
     */
    @Transactional(propagation= Propagation.REQUIRES_NEW)
    public void harvestn(Whinform wif) {
        generateWhinCopyData(wif, WhinformTypeEnums.HARVEST.getCode(),KDWhinformTypeEnums.PURCHASING.getCode());
    }


    /**
     * 生产加工入库
     *
     * @param wif
     */
    @Transactional(propagation= Propagation.REQUIRES_NEW)
    public void productionIn(Whinform wif) {
//        generateWhinCopyData(wif, WhinformTypeEnums.PRODUCTION.getCode(),KDWhinformTypeEnums.PURCHASING.getCode());
        //5-24修改
        generateWhinCopyData(wif, WhinformTypeEnums.PRODUCTION.getCode(),KDWhinformTypeEnums.PRODUCTION.getCode());
    }

    /**
     * 其他入库（调整入库）
     *
     * @param wif
     */
    @Transactional(propagation= Propagation.REQUIRES_NEW)
    public void justingIn(Whinform wif) {
        generateWhinCopyData(wif, WhinformTypeEnums.JUSTING.getCode(),KDWhinformTypeEnums.OTHER.getCode());
    }

    /**
     * 调拨出库单
     */
    @Transactional(propagation= Propagation.REQUIRES_NEW)
    public void redeployOut(Whoutform wof,Copyparam copyparam) {


        Transferapply apply=transferapplyService.selectTransferapplyById(wof.getOrderguid());
        if(apply.getStatus()!=100){
            //处理未完成数据
            DataexStopedtrans stoppers=new DataexStopedtrans();
            stoppers.setWhoutAutoid(wof.getAutoid());
            stoppers.setBusinessCode(wof.getBusinesscode());
            //20230704 首先检查是否已存在
            List<DataexStopedtrans> stopList = stopedtransService.selectDataexStopedtransList(stoppers);
            if(stopList.size()==0){
                stopedtransService.insertDataexStopedtrans(stoppers);
            }
        }else{
            Copytokd copytokd = new Copytokd();
//            if (wof.getOrgguid().equals(wof.getSettlOrgId())){
//                //同组织调拨
//                generateWhoutCopyData(copytokd,wof,null,WhoutformTypeEnums.REDEPLOY.getCode(), 1,false,KDWhoutformTypeEnums.OTHER.getCode(),null);
//            } else {
//                 //跨组织调拨
//                processTransOutForDifOrgs(wof,copyparam);
//            }
            if (!wof.getOrgguid().equals(wof.getSettlOrgId())){
                //跨组织调拨
                processTransOutForDifOrgs(wof,copyparam);
            }
        }
    }


    /**
     * 调整出库
     *
     * @param whoutform
     * @param date
     */
    @Transactional(propagation= Propagation.REQUIRES_NEW)
    public void justingOut(Whoutform whoutform, Date date) {
        Copytokd copytokd = new Copytokd();
        generateWhoutCopyData(copytokd,whoutform,null,WhoutformTypeEnums.JUSTING.getCode(),1, false,KDWhoutformTypeEnums.OTHER.getCode(), null);
    }

    /**
     * 报废出库
     *
     * @param whoutform
     * @param date
     */
    @Transactional(propagation= Propagation.REQUIRES_NEW)
    public void scrappingOut(Whoutform whoutform, Date date) {
        Copytokd copytokd = new Copytokd();
        generateWhoutCopyData(copytokd,whoutform,null,WhoutformTypeEnums.JUSTING.getCode(),1, false,KDWhoutformTypeEnums.OTHER.getCode(), null);
    }


    /**
     * 生产领料出库
     * 从生产报表中获取数据
     *
     * @param startDate
     * @param copyparam
     */
    @Transactional(propagation= Propagation.REQUIRES_NEW)
    public void productionOut(Date startDate, Copyparam copyparam) {
        Date date = DateUtils.getNowDate();

        Copytokd copytokdS = new Copytokd();
        copytokdS.setType(BillTypeEnums.OUT.getCode());
        copytokdS.setSubtype(WhoutformTypeEnums.PRODUCTION.getCode());
        Long autoid = this.copytokdService.getMaxlinkedid(copytokdS);
        Producereport producereport = new Producereport();
        if (StringUtils.isNotEmpty(copyparam.getConditions())) {
            producereport.setConditions(copyparam.getConditions());
        }
        List<Producereport> producereportList=new ArrayList<>();
        if (autoid > 0) {
            producereport.setId(autoid);
            producereportList= this.producereportService.selectProducereportListAll(producereport);
        }else{
            producereport.setBeginCreatedate(startDate);
            producereport.setEndCreatedate(DateUtils.getDateBeforeMinite(date, -3));
            producereportList= this.producereportService.selectProducereportListAll(producereport);
        }
        for (Producereport p : producereportList) {
            getProductionI(p);

            Copytokd copytokd = new Copytokd();
            copytokd.setCopyRemark("");
            copytokd.setLinkedautoid(p.getId());
            //出库单编号，生产报表中可能没有？
//            copytokd.setlinkedcode(p.)
            copytokd.setOrderguid(p.getPlanguid());
            copytokd.setCode(p.getPlcode());
            copytokd.setKdcode(p.getPlcode() + "A" + i);
            copytokd.setType(BillTypeEnums.OUT.getCode());
            copytokd.setSubtype(WhoutformTypeEnums.PRODUCTION.getCode());
            copytokd.setKdtype(KDWhoutformTypeEnums.PRODUCTION.getCode());
            copytokd.setSrguid(p.getSrguid());
            copytokd.setDepartmentid(p.getDepartid());
            copytokd.setOrgguid(p.getOrgguid());
            copytokd.setOrgname(p.getOrgname());
            copytokd.setTotalqty(p.getOutweight());
            copytokd.setOperator(p.getOperatorid());
            copytokd.setOrderdate(p.getOrderdate());
            copytokd.setCopyTime(date);
            copytokd.setLastCopyTime(date);
            copytokd.setCreatetime(date);
            copytokd.setIssplit(IssplitEnums.NO.getCode());
            copytokd.setStatus(CopyStatusEnums.INIT.getCode());
            this.copytokdService.insertCopytokd(copytokd);
            Long copyid = copytokd.getId();
            if (p.getProducereportitemList() != null) {
                for (int z = 0; z < p.getProducereportitemList().size(); z++) {
                    Producereportitem item = p.getProducereportitemList().get(z);
                    Copytokditem copytokditem = new Copytokditem();
                    copytokditem.setCopyRemark("");
                    copytokditem.setCtkdid(copyid);
                    copytokditem.setSrguid(p.getSrguid());
                    copytokditem.setShrguid(item.getShrguid());
                    copytokditem.setOrgguid(p.getOrgguid());
                    copytokditem.setOrgname(p.getOrgname());
                    copytokditem.setProductguid(item.getOutproductid());
                    copytokditem.setSpguid(item.getOutspecid());
                    copytokditem.setDepartmentid(p.getDepartid());
                    copytokditem.setOwner(p.getOperatorid());
                    copytokditem.setQty(item.getOutweight());
                    //2 辅料
                    if (p.getIntype() == 2) {
                        copytokditem.setUnit(item.getOutstockunit());
                        copytokditem.setUnitid(item.getOutstockunitid());
                    }else{
                        copytokditem.setUnit(item.getInstockunit());
                        copytokditem.setUnitid(item.getInstockunitid());
                    }
                    copytokditem.setStatus(CopyStatusEnums.INIT.getCode());
                    copytokditem.setPrice(BigDecimal.ZERO);
                    copytokditem.setCosguid(item.getCospguid());
                    copytokditem.setCopyTime(date);
                    copytokditem.setLastCopyTime(date);
                    copytokditem.setCreatedate(date);
                    copytokditem.setLastupdatetime(date);
                    this.copytokditemService.insertCopytokditem(copytokditem);
                }
            }
//            this.copytokdService.updatePickinglist(p.getPlcode());
        }

    }

    @Transactional(propagation= Propagation.REQUIRES_NEW)
    public void saleOut(Whoutform whoutform, Date date) {
        Organization organization = this.organizationService.selectOrganizationById(whoutform.getSettlOrgId());

        Sellform sellform=null;
        MultipartConfig multipartConfig=null;
        //20231220 外部渠道，比如美团生成的出库单，不需要读取sellform，也不需要跨组织拆分
        if(!whoutform.isExternalChannel()){
            sellform = this.sellformService.selectSellformByGuid(whoutform.getOrderguid());
            multipartConfig = this.multipartConfigService.selectMultipartConfigBySellPayType(sellform.getPaytype());
        }
        //出库组织和销售组织相同的，不需要拆分，否则需要拆分
        Copytokd copytokd = null;
        if (whoutform.getOrgguid().equals(whoutform.getSettlOrgId())
                || multipartConfig == null) {
            copytokd = new Copytokd();
            String kingdeeType = KDWhoutformTypeEnums.SALE.getCode();
            //20231218 需要考虑美团餐饮的销售出库单处理，sellform==null
            if (sellform!=null && !normalSellForm(sellform.getPaytype())) {
                //样品赠送等，其他出库单
                kingdeeType = KDWhoutformTypeEnums.OTHER.getCode();
            }
            generateWhoutCopyData(copytokd, whoutform, sellform, WhoutformTypeEnums.SALE.getCode(), 1,false, kingdeeType, null);
        } else {
            generateSplitedRecord(whoutform, sellform, multipartConfig);
        }

    }

    /**
     * 获取递增金蝶编号
     *
     * @param businesscode
     * @return
     */
    public int getI(String businesscode) {
        i = this.copytokdService.getSort(businesscode);
        return i;
    }

    /**
     * 获取领料出库递增便阿红
     *
     * @param producereport
     */
    public void getProductionI(Producereport producereport) {
        i = this.copytokdService.getSort(producereport.getPlcode());
    }


    /**
     * 入库单获取数量和金蝶数量
     * <p>
     * 1、根据入库单明规格找物料
     * 2、查看物料金蝶单位
     * 3、查看物料库存单位
     * 4、看库存单位是否重量单位  是重量单位则转换，并写入金蝶数量  不是重量单位则将weight写入金蝶数量
     */
    public boolean getQtyIn(Copytokditem copytokditem, Whinformitem whinformitem) {
        String spguid;
        if (StringUtils.isNotEmpty(whinformitem.getSpguid())) {
            spguid = whinformitem.getSpguid();
        } else {
            spguid = whinformitem.getRawspguid();
        }

        BigDecimal qtyInKingdee = transToKdWeight(spguid,copytokditem.getQty(),copytokditem);
        if (qtyInKingdee == null){
            return false;
        }else{
            copytokditem.setKdqty(qtyInKingdee);
            return true;
        }
    }

    /**
     * 出库重量处理
     *
     * @param copytokditem
     * @param whoutformitem
     * @param type    销售订单的：正常（所有数量）、赠送部分、有赠送的情况下的结算部分
     *                或者非销售订单
     */
    public boolean setQtyOut(Copytokditem copytokditem, Whoutformitem whoutformitem, String type) {


        //销售出库单以外的，出库单的weight就是出库数量
        if(type.equals(IsPresentKDEnums.OTHERS.getCode())){
            copytokditem.setQty(whoutformitem.getWeight());
            copytokditem.setKdqty(whoutformitem.getWeight());
            return true;
        }

        //获取当前出库明细的物料信息
        List<Salesspecification> salesspecifications = salesspecificationList.stream().filter(s -> copytokditem.getSpguid().equals(s.getGuid())).collect(Collectors.toList());

        if (salesspecifications.size() != 1) {
            copytokditem.setCopyRemark(copytokditem.getCopyRemark() + "设置出库数量时物料信息有误," + copytokditem.getSpguid());
            return false;
        }

        //物料的库存单位Id
        Long materailStockUnitId = salesspecifications.get(0).getStockunitid();
        if (materailStockUnitId == null) {
            copytokditem.setCopyRemark(copytokditem.getCopyRemark() + "物料信息没有设置库存单位Id,");
            return false;
        }

        //物料库存单位
        List<Stockunit> stockunits = this.stockunitList.stream().filter(t -> materailStockUnitId.equals(t.getId())).collect(Collectors.toList());
        if (stockunits.size() != 1) {
            copytokditem.setCopyRemark(copytokditem.getCopyRemark() + "物料信息库存单位设置有误,");
            copytokditem.setStatus(CopyStatusEnums.CANT.getCode());
            return false;
        }

        BigDecimal whoutLoadCount = BigDecimal.ZERO;

        boolean stockUnitIsWeight = (stockunits.get(0).getIsUnit().equals(IsWeifhtUnitEnums.YES.getCode()));

        if (stockUnitIsWeight) {
            //库存单位是重量单位
            setQtyOutByWeight(copytokditem, whoutformitem, type);
            BigDecimal qtyInKingDee = transToKdWeight(copytokditem.getSpguid(),copytokditem.getQty(),copytokditem);
            if (qtyInKingDee == null){
                return false;
            }else{
                copytokditem.setKdqty(qtyInKingDee);
            }
        } else {
            //库存单位不是重量
            if (type.equals(IsPresentKDEnums.PRESENT_PART.getCode())) {
                //处理赠送部分数据
                whoutLoadCount = whoutformitem.getHandsel();
            } else if (type.equals(IsPresentKDEnums.SETTLE_PART.getCode())
                    && whoutformitem.getHandsel() != null) {
                //有赠送的情况下的需要结算的部分
                whoutLoadCount = whoutformitem.getWeight().subtract(whoutformitem.getHandsel());
            } else {
                //处理全部
                whoutLoadCount = whoutformitem.getWeight();
            }
            copytokditem.setQty(whoutLoadCount);
            copytokditem.setKdqty(whoutLoadCount);
            copytokditem.setLoadcount(whoutLoadCount);
        }
        return true;
    }


    /**
     * 库存单位是重量单位的，统计出库数量
     *
     * @param copytokditem
     * @param whoutformitem
     * @param type
     */
    private void setQtyOutByWeight(Copytokditem copytokditem, Whoutformitem whoutformitem, String type) {

        BigDecimal whoutWeight = BigDecimal.ZERO;
        BigDecimal whoutLoadCount = (whoutformitem.getLoadcount()==null?
                BigDecimal.ZERO:BigDecimal.valueOf(whoutformitem.getLoadcount()));
        BigDecimal hahdsel = (whoutformitem.getHandsel()==null?
                BigDecimal.ZERO:whoutformitem.getHandsel());
        if (type.equals(IsPresentKDEnums.PRESENT_PART.getCode())) {
            //处理赠送部分
            whoutWeight = whoutformitem.getHandselweight();
            whoutLoadCount = hahdsel;
        } else if (type.equals(IsPresentKDEnums.SETTLE_PART.getCode())
                && whoutformitem.getHandsel() != null) {
            //有赠送情况下的结算部分
            whoutWeight = whoutformitem.getWeight().subtract(whoutformitem.getHandselweight());
            whoutLoadCount = whoutLoadCount.subtract(hahdsel);
        } else {
            whoutWeight = whoutformitem.getWeight();
        }

        copytokditem.setQty(whoutWeight);
        copytokditem.setLoadcount(whoutLoadCount);
        return;
    }

    /**
     * 根据物料信息的设置，转换物料的ERP数量为对应的金蝶数量
     * @param spguid
     * @param erpQty
     * @return
     */
    private BigDecimal transToKdWeight(String spguid,BigDecimal erpQty ,Copytokditem copytokditem){
        //获取当前出库明细的物料信息
        List<Salesspecification> salesspecifications = salesspecificationList.stream().filter(s -> spguid.equals(s.getGuid())).collect(Collectors.toList());

        if (salesspecifications.size() != 1) {
            copytokditem.setCopyRemark(copytokditem.getCopyRemark()+ "转换为金蝶数量时物料信息有误,"+ spguid);
            return null;
        }

        //物料的金蝶单位id
        Long materialKdunitId = salesspecifications.get(0).getKingdeeunitid();
        //物料的库存单位Id
        Long materailStockUnitId = salesspecifications.get(0).getStockunitid();


        if (materialKdunitId == null) {
            copytokditem.setCopyRemark(copytokditem.getCopyRemark() + "物料信息没有设置金蝶单位,");
            return null;
        }

        if (materailStockUnitId == null) {
            copytokditem.setCopyRemark(copytokditem.getCopyRemark()+ "物料信息没有设置库存单位Id,");
            return null;
        }

        //物料库存单位、金蝶单位信息
        List<Stockunit> stockunits = this.stockunitList.stream().filter(t -> materailStockUnitId.equals(t.getId())).collect(Collectors.toList());
        List<Stockunit> stockKDunits = this.stockunitList.stream().filter(t -> materialKdunitId.equals(t.getId())).collect(Collectors.toList());

        if (stockunits.size() != 1) {
            copytokditem.setCopyRemark(copytokditem.getCopyRemark()+ "物料信息库存单位设置有误,");
            return null;
        }

        if (stockKDunits.size() != 1) {
            copytokditem.setCopyRemark(copytokditem.getCopyRemark()+ "物料信息金蝶单位设置有误,");
            return null;
        }

        BigDecimal materialStockUnitToT = stockunits.get(0).getToT();
        BigDecimal materialKDUnitTot = stockKDunits.get(0).getToT();

        boolean stockUnitIsWeight = (stockunits.get(0).getIsUnit().equals(IsWeifhtUnitEnums.YES.getCode()));
        if (stockUnitIsWeight) {
            //库存单位是重量单位
            return erpQty.multiply(materialStockUnitToT).divide(materialKDUnitTot);
        }else{
            return erpQty;
        }
    }
    /**
     * 设置销售订单推送金蝶的单价及金额
     *
     * @param copytokditem
     * @param whoutformitem
     * @param type          1 - 内部结算价格 2- 对外销售价格
     * @param sellform
     * @return
     */
    private boolean setPriceAndAmount(Copytokd copytokd,Copytokditem copytokditem,Whoutform whoutform, Whoutformitem whoutformitem, int type, Sellform sellform) {
        //20230324 统一调用单价处理逻辑
        return innerPriceProcess.setPriceAndAmount(copytokd,copytokditem,whoutform,whoutformitem,sellform);
        /**
        boolean result = true;
        if (sellform == null){
            copytokditem.setPrice(whoutformitem.getPrice());
            //查一下调拨单的金额在出库明细表里有没有，有的话赋值，没有的话计算一下
            copytokditem.setAmount(whoutformitem.getPrice().multiply(copytokditem.getKdqty()));
            return result;
        }

        if (type == 1) {
            result = setInnerSettlePriceAndAmount(copytokditem, whoutformitem, sellform);
        } else {
            result = setToCustomerPriceAndAmount(copytokditem, whoutformitem, sellform);
        }
        return result;
         **/
    }

    /**
     * 设置销售订单的最终销售价格及结算金额
     * @param copytokditem
     * @param whoutformitem
     * @param sellform
     * @return
     */
    private boolean setToCustomerPriceAndAmount(Copytokditem copytokditem, Whoutformitem whoutformitem, Sellform sellform) {
        //获取当前出库明细的物料信息
        List<Salesspecification> salesspecifications = salesspecificationList.stream().filter(s -> copytokditem.getSpguid().equals(s.getGuid())).collect(Collectors.toList());

        if (salesspecifications.size() != 1) {
            copytokditem.setCopyRemark(copytokditem.getCopyRemark() + "设置对外价格及金额时物料信息有误,"+copytokditem.getSpguid());
            return false;
        }

        //获取当前物料的销售单位
        Long materailSfUnitId = salesspecifications.get(0).getSfunitid();
        List<Stockunit> sellunit = this.stockunitList.stream().filter(s -> materailSfUnitId.equals(s.getId())).collect(Collectors.toList());
        if (sellunit.size() == 0) {
            copytokditem.setCopyRemark(copytokditem.getCopyRemark() + "物料销售单位设置有误,for " + materailSfUnitId);
            return false;
        }
        Stockunit saleStockUnit = sellunit.get(0);

        BigDecimal price = BigDecimal.ZERO;
        if (saleStockUnit.getIsUnit().equals(IsWeifhtUnitEnums.NO.getCode())) {
            //物料的销售单位是按件数
            price = whoutformitem.getPrice();
            setCopytokdAmount(copytokditem,price.multiply(copytokditem.getLoadcount()));
//            copytokditem.setAmount(price.multiply(new BigDecimal(whoutformitem.getLoadcount())));
            copytokditem.setPrice(copytokditem.getAmount().divide(copytokditem.getKdqty(), 6));
            return true;
        }

        //销售订单的单价转换为按KG计算的单价，金蝶的重量单位是KG
        price = whoutformitem.getPrice().multiply(sellunit.get(0).getToKg());

        copytokditem.setPrice(price);
        setCopytokdAmount(copytokditem,price.multiply(copytokditem.getKdqty()));
//        copytokditem.setAmount(price.multiply(copytokditem.getKdqty()));

        return true;
    }

    /**
     * 处理内部结算价格（销售订单或调拨单）
     *
     * @param copytokditem
     * @param whoutformitem
     * @param sellform
     * @return
     */
    private boolean setInnerSettlePriceAndAmount(Copytokditem copytokditem, Whoutformitem whoutformitem, Sellform sellform) {
        //获取当前出库明细的物料信息
        List<Salesspecification> salesspecifications = salesspecificationList.stream().filter(s -> copytokditem.getSpguid().equals(s.getGuid())).collect(Collectors.toList());

        if (salesspecifications.size() != 1) {
            copytokditem.setCopyRemark(copytokditem.getCopyRemark() + "设置内部价格时物料信息有误," + copytokditem.getSpguid());
            return false;
        }


        //物料是标品还是非标品
        Integer priceFlag = salesspecifications.get(0).getInnerSettlePriceFlag();
        if (null == priceFlag){
            return false;
        }

        int innerSettlePriceFlag = priceFlag;

        //标品的内部结算价格，在数据加工过程处理
        if (1 == innerSettlePriceFlag) {
            return true;
        }
        //销售价格
        if (2 == innerSettlePriceFlag){
            return setInnerSettlePriceAndAmountForRate(copytokditem, whoutformitem.getPrice(), sellform, salesspecifications, BigDecimal.ZERO, BigDecimal.ZERO);
        }
        //固定毛利率
        if (3 == innerSettlePriceFlag){
            String innerSettlePrice_FixedRate = sysConfigService.selectConfigByKey("innerSettlePrice_FixedRate");
            BigDecimal rate = new BigDecimal(innerSettlePrice_FixedRate);
            return setInnerSettlePriceAndAmountForRate(copytokditem, whoutformitem.getPrice(), sellform, salesspecifications, rate, BigDecimal.ZERO);
        }
        //固定毛利额
        if (4 == innerSettlePriceFlag){
            String innerSettlePrice_FixAmount = sysConfigService.selectConfigByKey("innerSettlePrice_FixAmount");
            BigDecimal amount = new BigDecimal(innerSettlePrice_FixAmount);
            return setInnerSettlePriceAndAmountForRate(copytokditem, whoutformitem.getPrice(), sellform, salesspecifications, BigDecimal.ZERO, amount);
        }
        return true;
    }

    /**
     * 通过物料内部结算单价Flag计算单价
     * @param copytokditem
     * @param sellform
     * @param salesspecifications
     * @return
     */
    public boolean setInnerSettlePriceAndAmountForRate(Copytokditem copytokditem, BigDecimal sellPrice, Sellform sellform
            , List<Salesspecification> salesspecifications, BigDecimal rate, BigDecimal amount) {
        //非标品
        //赠送类的（赠送、样品，促销）等，非标品按参数中的内部价格
        if (!normalSellForm(sellform.getPaytype())) {
            if (innPrice == null) {
                copytokditem.setCopyRemark(copytokditem.getCopyRemark() + "需要为非标品设置内部结算价参数,");
                return false;
            } else {
                copytokditem.setPrice(innPrice);
                setCopytokdAmount(copytokditem, copytokditem.getPrice().multiply(copytokditem.getKdqty()));
//                copytokditem.setAmount(copytokditem.getPrice().multiply(copytokditem.getKdqty()));
                return true;
            }
        }

        //正常的、非赠送类的订单

        //如果销售订单是折扣订单，必须获取到折扣参数
        if (sellform.getIsdiscount() == 1 && innDiscount == null) {
            copytokditem.setCopyRemark(copytokditem.getCopyRemark() + "没有找到折扣参数,");
            return false;
        }

        //获取当前物料的销售单位
        Salesspecification salesspecification=salesspecifications.get(0);
        Long materailSfUnitId = salesspecification.getSfunitid();

        List<Stockunit> sellunit = this.stockunitList.stream().filter(s -> materailSfUnitId.equals(s.getId())).collect(Collectors.toList());
        if (sellunit.size() == 0) {
            copytokditem.setCopyRemark(copytokditem.getCopyRemark() + "物料销售单位设置有误 for ,"+ materailSfUnitId);
            return false;
        }
        Stockunit saleStockUnit = sellunit.get(0);

        BigDecimal price = BigDecimal.ZERO;
        if (saleStockUnit.getIsUnit().intValue() != 1) {
            //物料的销售单位是按件数，基本没有这种情况，暂时按照以下逻辑处理
            BigDecimal netWeight=salesspecification.getNetweight();
            price = sellPrice.divide(netWeight,6, BigDecimal.ROUND_DOWN);
            price = price.multiply(BigDecimal.ONE.subtract(rate)).subtract(amount);
            //setCopytokdAmount(copytokditem,price.multiply(new BigDecimal(whoutformitem.getLoadcount())));
//            copytokditem.setAmount(price.multiply(new BigDecimal(whoutformitem.getLoadcount())));
            copytokditem.setPrice(price);
            setCopytokdAmount(copytokditem,price.multiply(copytokditem.getKdqty()));
            return true;
        }

        //销售订单的单价转换为按KG计算的单价，金蝶的重量单位是KG
        price = sellPrice.multiply(sellunit.get(0).getToKg());
        price = price.multiply(BigDecimal.ONE.subtract(rate)).subtract(amount);


        //折扣处理
        if (sellform.getIsdiscount() == 1) {
            price = price.multiply(BigDecimal.ONE.subtract(innDiscount));
        }

        copytokditem.setPrice(price);
        setCopytokdAmount(copytokditem,price.multiply(copytokditem.getKdqty()));
//        copytokditem.setAmount(price.multiply(copytokditem.getKdqty()));

        return true;
    }

    /**
     * 根据ERP出库数据生成待推送出库数据
     *
     * @param whoutform ERP系统出库类型
     * @param sellform
     * @param whoutType
     * @param whouseType 1 - 从原始库房出库，2 - 从销售中转库出库
     * @param splitedRecord 是否是拆分订单的主数据，拆分订单的主数据不推送
     */
    public void generateWhoutCopyData(Copytokd copytokd, Whoutform whoutform, Sellform sellform,
                                      int whoutType,int whouseType, boolean splitedRecord, String KingDeeType, Long parentId) {
        setKdFromWhout(copytokd, whoutform, whoutType, splitedRecord,KingDeeType);

        if (KingDeeType != null) {
            copytokd.setKdtype(KingDeeType);
        }

        if (sellform != null ){
//            copytokd.setKdsellpaytype(String.valueOf(sellform.getPaytype()));
            copytokd.setSellpaytype(sellform.getPaytype());
        }

        //如果是拆分数据则处理主数据id
        if (parentId != null) {
            copytokd.setParentid(parentId);
            copytokd.setIssplit(IssplitEnums.YES.getCode());
        }
        //写入主表数据
        this.copytokdService.insertCopytokd(copytokd);

        //处理明细数据，后期优化为懒加载
        if (whoutform.getWhoutformitemList() == null) {
            return;
        }
        //拆分数据的最后一条数据，需要做特殊处理
        boolean lastDataForsplited = false;
        if (parentId != null  && sellform != null){
            lastDataForsplited = sellform.getSorgguid().equals(whoutform.getOrgguid());
        }
        //拆分数据的最后一条，或者非拆分数据，是面向最终客户的数据
        boolean finalToCustomer = ((parentId == null && !splitedRecord) || lastDataForsplited) ;

        for (Whoutformitem item : whoutform.getWhoutformitemList()) {

            if (item.getWeight().compareTo(BigDecimal.ZERO) != 0) {
                Copytokditem copytokditem = new Copytokditem();
                boolean successFlag = true;
                //从ERP出库明细设置待同步明细数据
                setKdItemFromWhoutItem(copytokd, copytokditem, whoutform, item);

                //如果是销售中转库的设置库间为空，数据加工补齐
                if (whouseType != 1 ){
                    copytokditem.setSrguid(copytokd.getSrguid());
                    copytokditem.setShrguid(null);
                }

                //设置qty及kdQty,如果是拆分数据的最后一条，只处理结算部分，否则，处理全部数据
                if (whoutType != WhoutformTypeEnums.SALE.getCode()){
                    successFlag = setQtyOut(copytokditem, item, IsPresentKDEnums.OTHERS.getCode());
                }
                else if (finalToCustomer) {
                    successFlag = setQtyOut(copytokditem, item, IsPresentKDEnums.SETTLE_PART.getCode());
                } else {
                    successFlag = setQtyOut(copytokditem, item, IsPresentKDEnums.ALL.getCode());
                }

                //处理价格及结算金额
                boolean priceProcessFlag = true;
                if (copytokd.getKdtype().equals(KDWhoutformTypeEnums.SALE.getCode())){
                    int innerOrOut = (finalToCustomer ? 2 : 1);
                    //20230324 调用价格统一处理逻辑
                    priceProcessFlag = setPriceAndAmount(copytokd,copytokditem,whoutform, item, innerOrOut, sellform);
                }

                //针对 调拨调差 差额 设置 单价及金额
                if (copytokd.getKdtype().equals(KDWhoutformTypeEnums.OTHER.getCode())){
                    if(item.getPrice()!=null&&copytokditem.getKdqty()!=null){
                        copytokditem.setPrice(item.getPrice());
                        copytokditem.setAmount(item.getPrice().multiply(copytokditem.getKdqty()));
                    }
                }

                successFlag = successFlag && priceProcessFlag;

                if (successFlag) {
                    copytokditem.setStatus(CopyStatusEnums.INIT.getCode());
                } else {
                    copytokditem.setStatus(CopyStatusEnums.CANT.getCode());
                }

                //写入明细信息
                this.copytokditemService.insertCopytokditem(copytokditem);

                //随车赠送数量>0,非拆分的数据、或者拆分数据的最后一条才处理
                if (item.getHandsel() != null &&
                        item.getHandsel().compareTo(BigDecimal.ZERO) != 0 && finalToCustomer) {
                    Copytokditem copytokditemHs = new Copytokditem();

                    setKdItemFromWhoutItem(copytokd, copytokditemHs, whoutform, item);

                    //如果是销售中转库的，设置库间为空，数据加工补齐
                    if (whouseType != 1 ){
                        copytokditemHs.setSrguid(copytokd.getSrguid());
                        copytokditemHs.setShrguid(null);
                    }
                    //推送金蝶销售订单、明细类型为赠送
                    copytokditemHs.setIspresent(IsPresentKDEnums.TRUE.getCode());
                    //设置qty及kdQty
                    successFlag = setQtyOut(copytokditemHs, item, IsPresentKDEnums.PRESENT_PART.getCode());
                    //赠送部分的单价金额
                    boolean setPriceFlag = setPriceAndAmount(copytokd,copytokditemHs,whoutform,item,2,sellform);
                    successFlag = successFlag && setPriceFlag;
                    if (successFlag) {
                        copytokditemHs.setStatus(CopyStatusEnums.INIT.getCode());
                    } else {
                        copytokditemHs.setStatus(CopyStatusEnums.CANT.getCode());
                    }
                    this.copytokditemService.insertCopytokditem(copytokditemHs);
                }
            }
        }
    }

    private void setKdFromWhout(Copytokd copytokd, Whoutform whoutform
            , int whoutType,  boolean splitedRecord,String KingDeeType) {
        Date date = DateUtils.getNowDate();
        getI(whoutform.getBusinesscode());

        copytokd.setCopyRemark("");
        copytokd.setLinkedautoid(whoutform.getAutoid());
        //业务编号
        copytokd.setOrderguid(whoutform.getGuid());
        copytokd.setCode(whoutform.getBusinesscode());
        copytokd.setLinkedcode(whoutform.getWhoutcode());
        copytokd.setKdcode(whoutform.getBusinesscode() + "A" + i);
        copytokd.setDepartmentid(whoutform.getDepartmentid());
        //调拨
        //销售订单
        if (KingDeeType.equals(KDWhoutformTypeEnums.SALE.getCode())||KingDeeType.equals(KDWhoutformTypeEnums.REDEPLOY.getCode())) {
            copytokd.setKdtype(KDWhoutformTypeEnums.SALE.getCode());
            //销售出库单，需要客户信息
            if (whoutform.getRevCustId() == null) {
                copytokd.setCopyRemark(copytokd.getCopyRemark() + "没有客户id");
            } else {
                copytokd.setCustomerid(whoutform.getRevCustId());
                copytokd.setCustomername(whoutform.getRevCustName());
            }
        } else {
            copytokd.setKdtype(KDWhoutformTypeEnums.OTHER.getCode());
        }


        copytokd.setType(BillTypeEnums.OUT.getCode());
        //子类型，需要验证一下是否正确
        copytokd.setSubtype(whoutType);

        //出库库房
        copytokd.setSrguid(whoutform.getSrguid());
        copytokd.setCurrency(whoutform.getCurrency());
        //库存组织
        copytokd.setOrgguid(whoutform.getOrgguid());
        copytokd.setOrgname(whoutform.getOrgname());

        copytokd.setTotalqty(whoutform.getWeight());

        copytokd.setOperator(whoutform.getOperatorid());
        //20231129统一用出库单的创建时间作为业务时间
        //copytokd.setOrderdate(whoutform.getOuttime());
        copytokd.setOrderdate(whoutform.getCreatetime());
        copytokd.setCopyTime(date);
        copytokd.setLastCopyTime(date);
        copytokd.setCreatetime(date);
        copytokd.setIssplit(IssplitEnums.NO.getCode());
        if (splitedRecord) {
            copytokd.setStatus(CopyStatusEnums.SPLIT.getCode());
        } else {
            copytokd.setStatus(CopyStatusEnums.INIT.getCode());
        }
        return;
    }

    /**
     * 通过ERP系统出库明细数据生成待推送明细数据的通用部分，不符合部分由调用方在方法执行完成后覆盖
     *
     * @param copytokd
     * @param copytokditem
     * @param whoutform
     * @param whoutItem
     */
    private void setKdItemFromWhoutItem(Copytokd copytokd, Copytokditem copytokditem, Whoutform whoutform,
                                        Whoutformitem whoutItem) {

        Date date = DateUtils.getNowDate();
        copytokditem.setCopyRemark("");
        copytokditem.setCtkdid(copytokd.getId());
        copytokditem.setSrguid(whoutItem.getSrguid());
        copytokditem.setShrguid(whoutItem.getShrguid());
        copytokditem.setOrgguid(whoutform.getOrgguid());
        copytokditem.setOrgname(whoutform.getOrgname());
//        copytokditem.setOrgname(whoutItem.getOrgname());
        copytokditem.setProductguid(whoutItem.getProductguid());
        copytokditem.setSpguid(whoutItem.getSpguid());

        //库存组织
        copytokditem.setSaleorgid(whoutform.getOrgguid());

        copytokditem.setOwner(whoutform.getOperatorid());
        copytokditem.setUnit(whoutItem.getStockunit());
        copytokditem.setUnitid(whoutItem.getStockunitid());
        copytokditem.setStatus(CopyStatusEnums.INIT.getCode());

        //设置客户id，无条件设置，数据加工逻辑已经调整过了，应该不需要判断条件了
        //whoutform.getOuttype().equals(WhoutformTypeEnums.SALE.getCode())&&
//        if (copytokd.getSellpaytype()!=null && normalSellForm(copytokd.getSellpaytype())) {
            copytokditem.setBalancecustomerid(whoutform.getRevCustId());
            copytokditem.setOrdercustomerid(whoutform.getRevCustId());
            copytokditem.setPaymentcustomerid(whoutform.getRevCustId());
            copytokditem.setOrdercustomerid(whoutform.getRevCustId());
//        }

        copytokditem.setKdupdatetype(KdUpdateTypeEnums.COMMONOUT.getCode());

        copytokditem.setCopyTime(date);
        copytokditem.setLastCopyTime(date);
        copytokditem.setCreatedate(date);
        copytokditem.setLastupdatetime(date);

        //20230306 写入新增的入库单详情的guid
        copytokditem.setWhinoroutitemGuid(whoutItem.getGuid());

        return;
    }

    /**
     * 根据销售订单的付款类型判断是否需要生成客户信息
     * 赠送、样品、促销等订单不需要客户数据
     *
     * @param payType
     * @return
     */
    private boolean normalSellForm(Integer payType) {
        if (payType == null) return false;
        return !(payType == 4 || payType == 5 || payType == 6);
    }

    /**
     * 销售订单的库存组织与销售组织不一致的时候，拆单处理
     *
     * @param whoutform
     * @param sellform
     * @param multipartConfig
     */
    private void generateSplitedRecord(Whoutform whoutform, Sellform sellform, MultipartConfig multipartConfig) {
        if (multipartConfig.getMultipartFlag().equals(MultipartEnums.NO.getCode())) {
            //参数设置本订单不需要集团参与内部结算
            doSplitRecord(whoutform, sellform, null);
        } else {
            //参数设置本订单需要集团参与结算
            if ((multipartConfig.getMultipartOrgguid().equals(whoutform.getOrgguid()))
                    || multipartConfig.getMultipartOrgguid().equals(whoutform.getSettlOrgId())) {
                //出库组织为集团,或者销售组织是集团，则集团不需要作为中间人结算
                doSplitRecord(whoutform, sellform, null);
            } else {
                //否则，集团作为中间人参与结算
                String orgId = multipartConfig.getMultipartOrgguid();
                List<Organization> organizations = organizationList.stream().filter(s -> orgId.equals(s.getGuid())).collect(Collectors.toList());
                doSplitRecord(whoutform, sellform, organizations.get(0));
            }
        }
    }

    /**
     * 根据中间组织middleOrg进行具体的订单拆分
     * 中间组织存在的情况下，订单拆分为5个子订单，否则为3个子订单
     *
     * @param whoutform
     * @param sellform
     * @param middleOrg
     */
    private void doSplitRecord(Whoutform whoutform, Sellform sellform, Organization middleOrg) {
        //库存组织id
        String stockOrgid = whoutform.getOrgguid();
        //销售组织id
        //20230307 销售组织id不从selform获取，改为从whoutform获取
        //String salesOrgid = sellform.getSorgguid();
        String salesOrgid =whoutform.getSettlOrgId();

        //中间商（集团）作为内部客户、内部供应商信息
        Customer customerForMiddleOrg = null;
        Supplier supplierForMiddleOrg = null;
        if (middleOrg != null){
            List<Customer> midCustomers = customerList.stream().filter(s -> middleOrg.getGuid().equals(s.getOrgguid())).collect(Collectors.toList());
            if (midCustomers.size() > 0) {
                customerForMiddleOrg = midCustomers.get(0);
            }else{
                log.error("cannt find inner customer for sellform :" + sellform.getSellcode()
                        +",for middle unit :"+middleOrg.getGuid());
                throw new RuntimeException();
            }
            List<Supplier> midSuppliers = supplierList.stream().filter(s -> middleOrg.getGuid().equals(s.getOrgguid())).collect(Collectors.toList());
            if (midSuppliers.size() > 0) {
                supplierForMiddleOrg = midSuppliers.get(0);
            }else{
                log.error("cannt find inner supplier for sellform :" + sellform.getSellcode()
                        +",for middle unit :"+middleOrg.getGuid());
                throw new RuntimeException();
            }
        }

        //库存组织对应的内部供应商
        Supplier supplierForStock = null;
        List<Supplier> stockSuppliers = supplierList.stream().filter(s -> stockOrgid.equals(s.getOrgguid())).collect(Collectors.toList());
        if (stockSuppliers.size() > 0) {
            supplierForStock = stockSuppliers.get(0);
        }else{
            log.info("cannt find inner supplier for sellform :" + sellform.getSellcode()
                    +",for stock unit :"+stockOrgid);
            throw new RuntimeException();
        }

        //销售组织信息
        List<Organization> salesorgs = organizationList.stream().filter(s -> salesOrgid.equals(s.getGuid())).collect(Collectors.toList());
        Organization salesorg = salesorgs.get(0);

        //销售组织对应的内部客户
        List<Customer> customers = customerList.stream().filter(s -> salesOrgid.equals(s.getOrgguid())).collect(Collectors.toList());
        Customer customerForSaleOrg = null;
        if (customers.size()>0){
            customerForSaleOrg = customers.get(0);
        }else{
            log.info("cannt find inner customer for sellform :" + sellform.getSellcode()
                    +",for sales unit :"+salesOrgid);
            throw new RuntimeException();
        }


        //最终客户
        List<Customer> realCustomers = customerList.stream().filter(s -> whoutform.getRevCustId().equals(s.getGuid())).collect(Collectors.toList());
        Customer realCustomer = realCustomers.get(0);

        //库存组织信息
        List<Organization> stockorgs = organizationList.stream().filter(s -> stockOrgid.equals(s.getGuid())).collect(Collectors.toList());
        Organization stockorg = stockorgs.get(0);

        //第一步，首先生成原始单据，状态为已拆分
        Copytokd copytokd = new Copytokd();
        generateWhoutCopyData(copytokd, whoutform, sellform, WhoutformTypeEnums.SALE.getCode(), 1,true, KDWhoutformTypeEnums.SALE.getCode(), null);
        Long parentKdId = copytokd.getId();

        //第二步，有中间商的，库存组织向中间商出库，否则，库存组织向销售组织出库,whouseType = 1 原始库房
        log.info("051600 2nd step:stock orgguid " + stockorg.getName() );
        if (middleOrg != null) {
            generateSplitedWhOutCopyData(whoutform,sellform,stockorg,customerForMiddleOrg,1,parentKdId);
        }else{
            generateSplitedWhOutCopyData(whoutform,sellform,stockorg,customerForSaleOrg,1,parentKdId);
        }

        //第三步，有中间商的，中间商向出库组织的采购入库
        if (middleOrg != null) {
            log.info("051600 3nd step:stock orgguid " + middleOrg.getGuid() );
            genarateSplitedWhinCopyData (whoutform, sellform, middleOrg, supplierForStock,  parentKdId);
        }
        //第四步，有中间商的，中间商销售出库给销售组织，whouseType = 2 销售中转库
        if (middleOrg != null) {
            log.info("051600 4th step:stock orgguid " + middleOrg.getGuid());
            generateSplitedWhOutCopyData(whoutform, sellform, middleOrg, customerForSaleOrg, 2, parentKdId);
        }

        //第五步，销售组织采购入库,有中间商向中间商采购，没有中间商向出库组织采购
        log.info("051600 5th step:stock orgguid " + salesorg.getGuid() );
        if(middleOrg != null){
            genarateSplitedWhinCopyData (whoutform, sellform, salesorg, supplierForMiddleOrg,  parentKdId);
        }else{
            genarateSplitedWhinCopyData (whoutform, sellform, salesorg, supplierForStock,  parentKdId);
        }

        //第六步，销售组织销售出库给最终客户，whouseType = 2 销售中转库
        log.info("051600 6th step:stock orgguid " + salesorg.getName() );
        generateSplitedWhOutCopyData(whoutform, sellform, salesorg, realCustomer, 2, parentKdId);

        return;
    }

    /**
     * 为组织生成该组织对某客户的销售中转库的销售出库数据
     *
     * @param whoutform
     * @param sellform
     * @param orgnazation  出库单所属组织
     * @param customer     销售单客户
     * @param whouseType   出库组织的库房性质  1 -- 原始库房 2---中转库房
     * @param parentCopyId
     */
    private void generateSplitedWhOutCopyData(Whoutform whoutform,
                                              Sellform sellform, Organization orgnazation, Customer customer, int whouseType, Long parentCopyId) {
        //当前组织如果是销售组织，并且销售订单为样品、赠送的，生成其他出库单，否则，销售出库单
        String kingdeeType = KDWhoutformTypeEnums.SALE.getCode();
        if (orgnazation.getGuid().equals(sellform.getSorgguid())
                && !normalSellForm(sellform.getPaytype())) {
            kingdeeType = KDWhoutformTypeEnums.OTHER.getCode();
        }

        //查找该组织的库房
        if (whouseType != 1){
            String storeRoomId = getStoreRoomIdByOrgId(orgnazation.getGuid());
            whoutform.setSrguid(storeRoomId);
        }
        whoutform.setOrgguid(orgnazation.getGuid());
        whoutform.setOrgname(orgnazation.getName());

        if (kingdeeType.equals(KDWhoutformTypeEnums.SALE.getCode())
                && customer != null) {
            whoutform.setRevCustId(customer.getGuid());
            whoutform.setRevCustName(customer.getName());
        }

        Copytokd copytokd = new Copytokd();
        generateWhoutCopyData(copytokd, whoutform, sellform, WhoutformTypeEnums.SALE.getCode(), whouseType,false, kingdeeType, parentCopyId);
    }

    /**
     * 内部结算的采购单
     * @param whoutform
     * @param sellform
     * @param orgnazation
     * @param supplier
     * @param parentCopyId
     */
    private void genarateSplitedWhinCopyData(Whoutform whoutform,
                                             Sellform sellform, Organization orgnazation, Supplier supplier,  Long parentCopyId) {
        log.info("Here we come into splited whin method for code " + sellform.getSellcode());
        getI(whoutform.getBusinesscode());
        Copytokd copytokd = new Copytokd();
        boolean successFlag = true;
        setKdFromWhout(copytokd, whoutform, 0, false,KDWhinformTypeEnums.PURCHASING.getCode());

        copytokd.setParentid(parentCopyId);
        if (supplier != null) {
            copytokd.setSupplierid(supplier.getId());
        } else {
            copytokd.setCopyRemark(copytokd.getCopyRemark() + "没有找到供应商数据,");
            successFlag = false;
        }

        String storeRoomId = getStoreRoomIdByOrgId(orgnazation.getGuid());
        if (storeRoomId != null) {
            copytokd.setSrguid(storeRoomId);
        } else {
            copytokd.setCopyRemark(copytokd.getCopyRemark() + "没有找到库房数据,");
            successFlag = false;
        }

        copytokd.setOrgguid(orgnazation.getGuid());
        copytokd.setOrgname(orgnazation.getName());

        copytokd.setIssplit(IssplitEnums.YES.getCode());
        copytokd.setType(BillTypeEnums.IN.getCode());
        copytokd.setKdtype(KDWhinformTypeEnums.PURCHASING.getCode());
        copytokd.setSubtype(WhinformTypeEnums.PURCHASING.getCode());
        if (successFlag) {
            copytokd.setStatus(CopyStatusEnums.INIT.getCode());
        } else {
            copytokd.setStatus(CopyStatusEnums.CANT.getCode());
        }
        this.copytokdService.insertCopytokd(copytokd);

//        Long copyiid = copytokdin.getId();
        if (whoutform.getWhoutformitemList() != null) {
            for (Whoutformitem item : whoutform.getWhoutformitemList()) {
                if (item.getWeight().compareTo(BigDecimal.ZERO) != 0) {
                    successFlag = true;
                    Copytokditem copytokditem = new Copytokditem();
                    setKdItemFromWhoutItem(copytokd, copytokditem, whoutform, item);
                    if (storeRoomId != null) {
                        copytokditem.setSrguid(storeRoomId);
                        copytokditem.setShrguid(null);
                    } else {
                        copytokditem.setCopyRemark(copytokd.getCopyRemark() + "没有找到库房数据,");
                        successFlag = false;
                    }

                    copytokditem.setOrgguid(orgnazation.getGuid());
                    copytokditem.setOrgname(orgnazation.getName());
                    copytokditem.setSaleorgid(orgnazation.getGuid());

                    copytokditem.setIspresent(IsPresentKDEnums.FALSE.getCode());
                    if (supplier != null) {
                        copytokditem.setSupplierid(supplier.getId());
                    } else {
                        copytokditem.setCopyRemark(copytokd.getCopyRemark() + "没有找到供应商数据,");
                        successFlag = false;
                    }
                    //数量
                    boolean qtySuccessFlag = setQtyOut(copytokditem,item,IsPresentKDEnums.ALL.getCode());
                    successFlag = successFlag && qtySuccessFlag;
                    //单价及金额
                    boolean priceProcessFlag = setPriceAndAmount(copytokd,copytokditem,whoutform,item,1,sellform);

                    successFlag = successFlag && priceProcessFlag;

                    if (item.getLoadcount() != null) {
                        copytokditem.setLoadcount(new BigDecimal(item.getLoadcount()));
                    } else {
                        copytokditem.setLoadcount(BigDecimal.ZERO);
                    }

                    if (successFlag) {
                        copytokditem.setStatus(CopyStatusEnums.INIT.getCode());
                    } else {
                        copytokditem.setStatus(CopyStatusEnums.CANT.getCode());
                    }
                    this.copytokditemService.insertCopytokditem(copytokditem);
                }
            }
        }
    }

    /**
     * 获取组织的销售中转库
     *
     * @param orgnazationsId
     * @return
     */
    public String getStoreRoomIdByOrgId(String orgnazationsId) {
        List<Storeroom> storerooms = storeroomList.stream().filter(s -> ("4".equals(s.getNature()) && orgnazationsId.equals(s.getOrgguid()))).collect(Collectors.toList());
        if (storerooms.size() == 1) {
            return storerooms.get(0).getGuid();
        }
        return null;
    }

    /**
     * 根据库房id以及库间类型，获取库间id
     *
     * @param storeRoomId
     * @param shType
     * @return
     */
    public String getStoreHouseIdBySrId(String storeRoomId, int shType) {
        if (storeRoomId == null) {
            return null;
        }
        List<Storehouseroom> storehouserooms = storehouseroomList.stream().filter(s -> (storeRoomId.equals(s.getStoreguid()))).collect(Collectors.toList());
        storehouserooms = storehouserooms.stream().filter(s -> shType == s.getShrtype()).collect(Collectors.toList());
        if (storehouserooms.size() > 0) {
            return storehouserooms.get(0).getGuid();
        }
        ;
        return null;
    }
}
